home *** CD-ROM | disk | FTP | other *** search
/ Pulps on CDRom / Pulps on CDROM.iso / comm.z / system.js < prev    next >
Text File  |  1998-10-20  |  23KB  |  801 lines

  1. /* ==================================================================
  2. FILE:   System.js
  3. DESCR:  System class for Netscape Help implementation.
  4. NOTES:  
  5. ================================================================== */
  6. // Dev. switches.
  7. var TRACE           = false
  8. var ASSERT          = true
  9. var ERR_DLGS        = true
  10. var ERRS_TO_CONSOLE = false
  11.  
  12. // "Constants."
  13. var VERSION         = "2.0"
  14. var LAYERED_TOPICS  = false
  15. var JAVA_DEPENDENT  = false
  16. var STAMP_CONSOLE   = false
  17. var OK_NAV_VERSIONS = ".4."
  18. var CHECK_HREFS     = false
  19. var CONTENTS        = "CntTool.htm"
  20. var INDEX           = "IdxTool.htm"
  21. var SEARCH          = "SrhTool.htm"
  22. var NAVUI           = "NavUI.htm"
  23. var TOOLUI          = "ToolUI.htm"
  24. var STATUS          = "Status.htm"
  25. var MESSAGE_BGCOLOR = "#fafad2"
  26. var TOOL_BGCOLOR    = "#99ccff"
  27.  
  28. //trace( "System.js" )
  29.  
  30. // Runtime error handling.
  31. // window.onerror = errHandler
  32.  
  33. // Version stamp.
  34. if ( STAMP_CONSOLE && navigator.javaEnabled() ) {
  35.    java.lang.System.out.println( "System.js, version " + VERSION )
  36.    java.lang.System.out.println( "Client: " + navigator.appVersion )
  37. }
  38.  
  39. /*
  40. DESCR:   Handles the onhelp event.
  41. PARAMS:  URL  The URL to load.
  42. RETURNS: 
  43. NOTES:   
  44. */
  45. function onHelpHandler( URL )
  46. {
  47.    //trace( "onHelpHandler(" + URL + ")" )
  48.    //alert( "onHelpHandler(" + URL + ")" )
  49.  
  50.    systemObj.loadTopic( URL, false )
  51. }
  52.  
  53. /*
  54. DESCR:   Traces execution to the console.
  55. PARAMS:  msg  The trace text.
  56. RETURNS: 
  57. NOTES:   
  58. */
  59. function trace( msg )
  60. {
  61.    if ( TRACE ) java.lang.System.out.println( "System: " + msg )
  62. }
  63.  
  64. // Create system object.
  65. var systemObj = new system( JAVA_DEPENDENT, OK_NAV_VERSIONS )
  66. assert( ( typeof( systemObj ) == "object" ), SYS_CONSTRUCT )
  67.  
  68. /*
  69. DESCR:   Help implementation system class.
  70. PARAMS:  bJavaDependent  Pass true if the system is Java dependent,
  71.                          false if not.
  72.          OKNavVersions   String representing valid versions of Navigator.
  73. RETURNS: 
  74. NOTES:   
  75. */
  76. function system( bJavaDependent, OKNavVersions )
  77. {
  78.    //trace( "system constructor" )
  79.  
  80.    this.backStack    = new stack()
  81.    this.forwardStack = new stack()
  82.  
  83.    this.navVersion
  84.    this.topic
  85.    this.contents
  86.  
  87.    //this.aSysSecWnds = new Array()  // Sys-owned secondary windows.
  88.  
  89.    this.currentTool       = CONTENTS  // Set default tool.
  90.    this.bIdxTitlesPageUp  = false
  91.    this.currentSubsystem  = ""
  92.    this.visibleLayerIdx   = ""
  93.  
  94.    this.bToolUIloaded   = false
  95.    this.bNavUIloaded    = false
  96.    this.bContentsLoaded = false
  97.    this.bIndexLoaded    = false
  98.    this.bStarted        = false
  99.  
  100.    this.bNewSubsystem = false
  101.  
  102.    this.preproc           = preproc
  103.    this.componentCallback = componentCallback
  104.    this.idxTitlesUp       = idxTitlesUp
  105.    this.loadTopic         = loadTopic
  106.    this.newSubsystem      = newSubsystem
  107.    this.exit              = exit
  108.    this.print             = print
  109.    this.back              = back
  110.    this.forward           = forward
  111.    //this.openSecWnd        = openSecWnd
  112.    this.loadTool          = loadTool
  113.    this.setToolButton     = setToolButton
  114.    this.msg               = msg
  115.    this.manageLayers      = manageLayers
  116.    this.badURLerror       = badURLerror
  117.  
  118.    this.componentsReadyEvt = componentsReadyEvt
  119.    this.loadEvt            = loadEvt
  120.    this.unloadEvt          = unloadEvt
  121.  
  122.    this.stashPersistentData  = stashPersistentData
  123.    this.snatchPersistentData = snatchPersistentData
  124.  
  125.    // Preprocessing.
  126.    if ( !this.preproc( bJavaDependent, OKNavVersions ) ) {
  127.       return
  128.    }
  129.  
  130.    // Load components.
  131.    top.StatusFrame.location.replace( STATUS )
  132.    top.ToolUIFrame.location.replace( TOOLUI )
  133.    top.NavFrame.location.replace( NAVUI )
  134.    top.ToolFrame.location.replace( this.currentTool )
  135. }
  136.  
  137.    /*
  138.    DESCR:   Pre-Help processing.
  139.    PARAMS:  bJavaDependent  Pass true if the system is Java dependent,
  140.                             false if not.
  141.             OKNavVersions   String representing valid versions of Navigator.
  142.    RETURNS: 
  143.    NOTES:   
  144.    */
  145.    function preproc( bJavaDependent, OKNavVersions )
  146.    {
  147.       //trace( "preproc()" )
  148.       
  149.       // Make sure Java is enabled if needed. Otherwise, abort.
  150.       if ( bJavaDependent && !navigator.javaEnabled() ) {
  151.          this.msg( NO_JAVA_ERR_MSG, "" )
  152.          return false
  153.       }
  154.  
  155.       // Validate version of navigator. Render in ".integer." form.
  156.       var version = navigator.appVersion
  157.       this.navVersion =
  158.          "." + version.substring( 0, ( version.indexOf( "." ) + 1 ) )
  159.       if ( OKNavVersions.indexOf( this.navVersion ) == -1 ) {
  160.          this.msg( WRONG_NAV_VER_ERR_MSG, "" )
  161.          return false
  162.       }
  163.  
  164.       return true
  165.    }
  166.  
  167.    /*
  168.    DESCR:   Tracks component loading.
  169.    PARAMS:  componentName  The document-name of the component.
  170.    RETURNS: 
  171.    NOTES:   Components call this method on load. Triggers ready
  172.             event when all loaded.
  173.    */
  174.    function componentCallback( componentName )
  175.    {
  176.       //trace( "componentCallback(" + componentName + ")" )
  177.       //alert( "componentCallback(" + componentName + ")" )
  178.  
  179.       // Track component loading.
  180.  
  181.       // Note: for some reason, can't write to status frame until Contents
  182.       // is loaded, so we do this later.
  183.       //if ( componentName == STATUS ) top.StatusFrame.setStatusWait()
  184.  
  185.       if ( componentName == TOOLUI ) this.bToolUIloaded = true
  186.  
  187.       if ( componentName == NAVUI ) this.bNavUIloaded = true
  188.  
  189.       if ( componentName == CONTENTS ) {
  190.  
  191.          // Keep house.
  192.          top.StatusFrame.setStatusWait()
  193.          top.ToolUIFrame.bDisableBtnBar = false
  194.          this.bContentsLoaded = true
  195.          this.bIndexLoaded = false
  196.  
  197.          // Create a Contents object.
  198.          this.contents = new top.ToolFrame.contents( TOOL_BGCOLOR )
  199.          assert( ( typeof( this.contents ) == "object" ), CNT_CONSTRUCT )
  200.  
  201.          // If this is not a system load and we're just changing to the
  202.          // Contents tool, set the Content's dataset and update. Otherwise,
  203.          // this will happen when a topic is loaded.
  204.          if ( this.bStarted ) {
  205.            this.contents.setDataset( this.currentSubsystem )
  206.            this.contents.updateTree( this.topic.URL )
  207.  
  208.            top.StatusFrame.setStatusClear()
  209.          }
  210.       }
  211.  
  212.       if ( componentName == INDEX ) {
  213.          top.ToolUIFrame.bDisableBtnBar = false
  214.          this.bIndexLoaded = true
  215.          this.bContentsLoaded = false
  216.  
  217.          if ( this.bStarted ) top.StatusFrame.setStatusClear()
  218.       }
  219.  
  220.       // Set the blender button down for the current tool.
  221.       if ( componentName == TOOLUI ) {
  222.          this.setToolButton( ( this.currentTool == CONTENTS ? 0 : 1 ), 1 )
  223.       }
  224.  
  225.       // Get moving if we're ready, but not already underway.
  226.       if ( !this.bStarted &&
  227.            this.bToolUIloaded && this.bNavUIloaded &&
  228.            ( this.bContentsLoaded || this.bIndexLoaded ) ) {
  229.          this.bStarted = true
  230.          this.componentsReadyEvt()   
  231.       }
  232.    }
  233.  
  234.    /*
  235.    DESCR:   Handles components ready "event."
  236.    PARAMS:  
  237.    RETURNS: 
  238.    NOTES:   
  239.    */
  240.    function componentsReadyEvt()
  241.    {
  242.       //trace( "componentsReadyEvt()" )
  243.  
  244.       // Set onhelp handler.
  245.       top.setOnhelpHandler( "onHelpHandler" )
  246.    }
  247.  
  248.    /*
  249.    DESCR:   Enables external state-setting of the tool UI button bar.
  250.    PARAMS:  buttonIdx  Identifies the button on the bar.
  251.             newState   The state to set.
  252.    RETURNS: 
  253.    NOTES:   
  254.    */
  255.    function setToolButton( buttonIdx, newState )
  256.    {
  257.       //trace( "setToolButton" )
  258.  
  259.       assert( defined( top.ToolUIFrame.btnBar ), TOOLUI )
  260.       if ( defined( top.ToolUIFrame.btnBar ) ) {
  261.  
  262.          // Set.
  263.          with ( top.ToolUIFrame.btnBar.aButtons[ buttonIdx ] ) {
  264.             setState( newState )
  265.             bOn = true
  266.          }
  267.       }
  268.    }
  269.  
  270.    /*
  271.    DESCR:   onload handler.
  272.    PARAMS:  
  273.    RETURNS: 
  274.    NOTES:   
  275.    */
  276.    function loadEvt()
  277.    {
  278.       //trace( "loadEvt()" )
  279.       //alert( "loadEvt()" )
  280.  
  281.       // Snatch important data for persistence on reload due to window resizing.
  282.       this.snatchPersistentData()
  283.    }
  284.  
  285.    /*
  286.    DESCR:   onunload handler.
  287.    PARAMS:  
  288.    RETURNS: 
  289.    NOTES:   
  290.    */
  291.    function unloadEvt()
  292.    {
  293.       //trace( "unloadEvt()" )
  294.       //alert( "unloadEvt()" )
  295.  
  296.       // Stash important data for persistence on reload due to window resizing.
  297.       this.stashPersistentData()
  298.  
  299.       // Clean up topic (topic-owned secondary windows, etc.).
  300.       if ( defined( this.topic ) ) this.topic.destruct()
  301.  
  302.       // Close any system-owned secondary windows.
  303.       //for ( var i = 0; i < this.aSysSecWnds.length; i++ ) {
  304.       //   if ( defined( this.aSysSecWnds[ i ] ) ) this.aSysSecWnds[ i ].close()
  305.       //}
  306.    }
  307.  
  308.    /*
  309.    DESCR:   Stores data needed to maintain state on reload due to resize.
  310.    PARAMS:  
  311.    RETURNS: 
  312.    NOTES:   
  313.    */
  314.    function stashPersistentData()
  315.    {
  316.       //trace( "stashPersistentData" )
  317.  
  318.       if ( defined( top.aPersistentData ) ) {
  319.          var i = 0
  320.          top.aPersistentData[ i++ ] = this.currentTool
  321.          top.aPersistentData[ i++ ] = this.forwardStack
  322.          top.aPersistentData[ i++ ] = this.backStack
  323.          //this.topic
  324.          //this.visibleLayerIdx
  325.       }
  326.    }
  327.  
  328.    /*
  329.    DESCR:   Retrieves data needed to maintain state on reload due to resize.
  330.    PARAMS:  
  331.    RETURNS: 
  332.    NOTES:   
  333.    */
  334.    function snatchPersistentData()
  335.    {
  336.       //trace( "snatchPersistentData" )
  337.  
  338.       if ( defined( top.aPersistentData[ 0 ] ) ) {
  339.          var i = 0
  340.          this.currentTool  = top.aPersistentData[ i++ ]
  341.          this.forwardStack = top.aPersistentData[ i++ ] 
  342.          this.backStack    = top.aPersistentData[ i++ ]
  343.       }
  344.    }
  345.  
  346.    /*
  347.    DESCR:   Loads the Contents, Index, or Find tool.
  348.    PARAMS:  toolName  The document-name of the tool.
  349.    RETURNS: 
  350.    NOTES:   
  351.    */
  352.    function loadTool( toolName )
  353.    {
  354.       //trace( "loadTool(" + toolName + ")" )
  355.  
  356.       assert( ( toolName == CONTENTS ||
  357.                 toolName == INDEX ||
  358.                 toolName == SEARCH ), TOOLNAME )
  359.  
  360.       // Contents tool.
  361.       if ( toolName == CONTENTS && !this.bContentsLoaded ) {
  362.  
  363.          // Keep house.
  364.          top.StatusFrame.setStatusWait()
  365.          top.ToolUIFrame.bDisableBtnBar = true
  366.  
  367.          top.ToolFrame.location.replace( toolName )
  368.       }
  369.  
  370.       // Index tool.
  371.       else if ( toolName == INDEX && !this.bIndexLoaded ) {
  372.  
  373.          // Keep house.
  374.          top.StatusFrame.setStatusWait()
  375.          top.ToolUIFrame.bDisableBtnBar = true
  376.  
  377.          top.ToolFrame.location.replace( toolName )
  378.       }
  379.  
  380.       // Search tool.
  381.       else if ( toolName == SEARCH ) {
  382.  
  383.          // We are using native find functionality in lieu of Search tool.
  384.          // Be sure to invoke Find against the topic frame.
  385.          top.TopicFrame.find()
  386.       }
  387.  
  388.       // Track current tool, but exempt the search tool since we are just
  389.       // using Find and we still have a Help tool loaded.
  390.       if ( toolName != SEARCH ) this.currentTool = toolName
  391.    }
  392.  
  393.    /*
  394.    DESCR:   Closes the Help window.
  395.    PARAMS:  
  396.    RETURNS: 
  397.    NOTES:   
  398.    */
  399.    function exit()
  400.    {
  401.       //trace( "exit()" )
  402.  
  403.       // Close frameset.
  404.       top.close()
  405.    }
  406.  
  407.    /*
  408.    DESCR:   Moves back in Help history.
  409.    PARAMS:  
  410.    RETURNS: 
  411.    NOTES:   Presumes button is disabled on empty stack.
  412.    */
  413.    function back()
  414.    {
  415.       //trace( "back()" )
  416.  
  417.       // Since the Index's titles page may be in the topic frame, but not
  418.       // part of history, we don't really wan't to go Back. Just restore
  419.       // the current topic without adding it to history.
  420.       if ( this.bIdxTitlesPageUp ) {
  421.          this.loadTopic( this.topic.URL, false )
  422.          return
  423.       }
  424.  
  425.       assert( !this.backStack.isEmpty(), BACK_STACK )
  426.       this.forwardStack.push( this.topic.URL )
  427.       this.loadTopic( this.backStack.pop(), true )
  428.    }
  429.  
  430.    /*
  431.    DESCR:   Moves forward in Help history.
  432.    PARAMS:  
  433.    RETURNS: 
  434.    NOTES:   Presumes button is disabled on empty stack.
  435.    */
  436.    function forward()
  437.    {
  438.       //trace( "forward()" )
  439.  
  440.       assert( !this.forwardStack.isEmpty(), FORWARD_STACK )
  441.       this.backStack.push( this.topic.URL )
  442.       this.loadTopic( this.forwardStack.pop(), true )
  443.    }
  444.  
  445.    /*
  446.    DESCR:   Tracks the Index's topic titles page in the topic window.
  447.    PARAMS:  
  448.    RETURNS: 
  449.    NOTES:   
  450.    */
  451.    function idxTitlesUp()
  452.    {
  453.       //trace ( "idxTitlesUp()" )
  454.       
  455.       this.bIdxTitlesPageUp = true
  456.  
  457.       // The Index titles page is not part of the topics history, so make
  458.       // sure that Forward is disabled and Back is enabled.
  459.       assert( defined( top.NavFrame.btnBar ), NAV_BAR )
  460.       if ( defined( top.NavFrame.btnBar ) ) {
  461.          top.NavFrame.btnBar.aButtons[ 0 ].enable( true )
  462.          top.NavFrame.btnBar.aButtons[ 1 ].enable( false )
  463.       }
  464.    }
  465.  
  466.    /*
  467.    DESCR:   Handles tasks when the Help subsystem changes.
  468.    PARAMS:  newSubsystem  A simple filename representing the subsystem
  469.                           (the topic filename).
  470.    RETURNS: 
  471.    NOTES:   
  472.    */
  473.    function newSubsystem( newSubsystem )
  474.    {
  475.       //trace( "newSubsystem('" + newSubsystem + "')" )
  476.       //alert( "newSubsystem('" + newSubsystem + "')" )
  477.  
  478.       assert( ( newSubsystem.toLowerCase().indexOf( ".htm" ) > -1 ),
  479.               SUBSYS_VALUE + newSubsystem )
  480.  
  481.       // Track the current subsystem.
  482.       this.currentSubsystem = newSubsystem
  483.  
  484.       // Reinitialize the visible layer index, since nothing is visible yet.
  485.       this.visibleLayerIdx = ""
  486.  
  487.       // Load the new header.
  488. //      top.HeaderFrame.location.replace( this.topic.headerURL )
  489.  
  490.       // Set the Contents tool's dataset.
  491.       if ( this.currentTool == CONTENTS ) {
  492.          this.contents.setDataset( newSubsystem )
  493.       }
  494.    }
  495.  
  496.    /*
  497.    DESCR:   Loads a topic.
  498.    PARAMS:  URL           The non-nethelp version of the URL.
  499.             bHistoryLoad  true if this is a load due to Back or Forward;
  500.                           false, otherwise.
  501.    RETURNS: 
  502.    NOTES:   
  503.    */
  504.    function loadTopic( URL, bHistoryLoad )
  505.    {
  506.       //trace( "loadTopic(" + URL + ")" )
  507.  
  508.       assert( ( URL.toLowerCase().indexOf( ".htm" ) > -1 ), URL_VALUE + URL )
  509.  
  510.       // Update Index titles page flag. If we are loading a topic, it can't
  511.       // be the URL in the topic window.
  512.       this.bIdxTitlesPageUp = false
  513.  
  514.       // Keep house if there is an existing topic...
  515.       if ( defined( this.topic ) ) {
  516.  
  517.          // Track as history, if this is _not_ a history load, and if we are
  518.          // not reloading the same URL for some (good) reason. Note that
  519.          // forward stack should be cleared.
  520.          if ( !bHistoryLoad && ( this.topic.URL != URL ) ) {
  521.             this.backStack.push( this.topic.URL )
  522.             this.forwardStack.clear()
  523.          }
  524.  
  525.          // "Destruct" the current topic.
  526.          this.topic.destruct()
  527.       } 
  528.  
  529.       // See if we need to change subsystems.
  530.       var bNewSubsystem =
  531.          ( makeSimpleFilename( URL ) != this.currentSubsystem ? true : false )
  532.  
  533.       // If we're loading a new topic file, set the wait indicator.
  534.       if ( bNewSubsystem ) top.StatusFrame.setStatusWait()
  535.  
  536.       // Create new topic object. Must happen before updating subsystem.
  537.       this.topic = new helpTopic( URL )
  538.       assert( ( typeof( this.topic ) == "object" ), TOPIC_CONSTRUCT )
  539.  
  540.       // Update current subsystem. Must happen before updating Contents tree
  541.       // or managing layers.
  542.       if ( bNewSubsystem ) this.newSubsystem( makeSimpleFilename( URL ) )
  543.  
  544.       // Enable/disable history buttons.
  545.       assert( defined( top.NavFrame.btnBar ), NAV_BAR )
  546.       if ( defined( top.NavFrame.btnBar ) ) {
  547.          var bEnable
  548.          bEnable = ( this.backStack.isEmpty() ? false : true )
  549.          top.NavFrame.btnBar.aButtons[ 0 ].enable( bEnable )
  550.          bEnable = ( this.forwardStack.isEmpty() ? false : true )
  551.          top.NavFrame.btnBar.aButtons[ 1 ].enable( bEnable )
  552.       }
  553.  
  554.       // Update Contents tree.
  555.       if ( this.currentTool == CONTENTS ) this.contents.updateTree( URL )
  556.  
  557.       // Layers are managed on topic file load (to ensure the layers exist),
  558.       // but since an anchor "load" in the current URL generates no load
  559.       // event, we need to call manageLayers() here under such conditions.
  560.       if ( LAYERED_TOPICS && !this.bNewSubsystem ) this.manageLayers()
  561.    }
  562.  
  563.    /*
  564.    DESCR:   Manages layers if layered topics is turned on.
  565.    PARAMS:  
  566.    RETURNS: 
  567.    NOTES:   This is called from the topic onload handler, to be sure the
  568.             document is loaded, or it is called from loadTopic() if the
  569.             subsystem has not changed, since such a load is via a named
  570.             anchor and does not raise an onload event. 
  571.    */
  572.    function manageLayers()
  573.    {
  574.       //trace( "manageLayers()" )
  575.  
  576.       if ( !LAYERED_TOPICS ) return
  577.  
  578.       // Bail if there are no layered topics.
  579.       if ( !defined( top.TopicFrame.document.layers[ 0 ] ) ) return
  580.  
  581.       // Hide any currently visible topic.
  582.       if ( this.visibleLayerIdx != "" ) {
  583.          top.TopicFrame.document.layers[ this.visibleLayerIdx ].hidden = true
  584.       }
  585.  
  586.       // Unhide the topic layer.
  587.       top.TopicFrame.document.layers[ this.topic.fragmentSpec ].hidden = false
  588.  
  589.       // Stash this index.
  590.       this.visibleLayerIdx = this.topic.fragmentSpec
  591.    }
  592.  
  593.    /*
  594.    DESCR:   Creates an always-on-top message box with an OK button.
  595.    PARAMS:  msgText     The message text.
  596.             msgCaption  The window caption.
  597.    RETURNS: 
  598.    NOTES:   The message box is asynchronous, except that the OK button's
  599.             window.close() will not execute until the JS in the calling
  600.             window executes. Note that parser can't hack whitespace in
  601.             third parm of open().
  602.    */
  603.    function msg( msgText, msgCaption )
  604.    {
  605.       //trace( "msg(" + msgText + ")" )
  606.  
  607.       if ( msgCaption == "" ) msgCaption = DEFAULT_MESSAGE_CAPTION
  608.  
  609.       var msgDlg =
  610.          window.open( "", "",
  611.                       "SCROLLBARS=no,WIDTH=350,HEIGHT=200,SCROLLBARS=yes,ALWAYSRAISED=yes,DEPENDENT=yes,TITLEBAR=no,MENUBAR=no,HOTKEYS=no" )
  612.  
  613.       var html
  614.       html = "<HEAD><TITLE>" + msgCaption +
  615.              "</TITLE></HEAD><BODY BGCOLOR = " + MESSAGE_BGCOLOR + ">"
  616.       html += msgText
  617.       html += "<BR><BR><BR><BR>"
  618.       html += "<CENTER><FORM METHOD = POST>"
  619.       html += "<INPUT TYPE = button NAME = 'OK' VALUE = '   " +
  620.               OK_BTN_LABEL +
  621.               "   ' ONCLICK = 'window.close()'></FORM></CENTER></BODY>"
  622.  
  623.       msgDlg.document.write( html )
  624.       msgDlg.document.close()
  625.    }
  626.  
  627.    /*
  628.    DESCR:   Creates a secondary content window.
  629.    PARAMS:  URL         The content URL.
  630.             name        The window name.
  631.             features    The feature string.
  632.             bSystem     true if the window should be system-owned (i.e.,
  633.                         window will not be closed when parent topic
  634.                         closes, only when the system shuts down);
  635.                         false, if topic-owned.
  636.             bReturnObj  true if the window object should be returned.
  637.    RETURNS: Optionally, the window object.
  638.    NOTES:   
  639.    */
  640.    /*
  641.    function openSecWnd( URL, name, features, bSystem, bReturnObj )
  642.    {
  643.       //trace( "openSecWnd(" + URL + ")" )
  644.  
  645.       // Create a system- or topic-owned seconadary window.
  646.       var newWnd
  647.       var bAlreadyExists = false
  648.       if ( bSystem ) {
  649.          newWnd = window.open( URL, name, features )
  650.  
  651.          // Add window to list only if it is a new window (user may create
  652.          // a secondary more than once).
  653.          for ( var i = 0; i < this.aSysSecWnds.length; i++ ) {
  654.             if ( this.aSysSecWnds[ i ] == newWnd ) {
  655.                if ( bReturnObj ) return newWnd
  656.                else bAlreadyExists = true
  657.             }
  658.          }
  659.          if ( !bAlreadyExists ) { 
  660.             this.aSysSecWnds[ this.aSysSecWnds.length ] = newWnd
  661.             if ( bReturnObj ) return newWnd
  662.          }
  663.       }
  664.       else {
  665.          newWnd = this.topic.addSecondary( URL, name, features )
  666.          if ( bReturnObj ) return newWnd
  667.       }
  668.    }
  669.    */
  670.  
  671.    /*
  672.    DESCR:   Creates a bad URL type error.
  673.    PARAMS:  href  The offending href.
  674.    RETURNS: 
  675.    NOTES:   
  676.    */
  677.    function badURLerror( href )
  678.    {
  679.       this.msg( BAD_HREF_ERR_MSG + "<P>" + href, "" )
  680.    }
  681.  
  682.    /*
  683.    DESCR:   Prints the content in the topic frame.
  684.    PARAMS:  
  685.    RETURNS: 
  686.    NOTES:   
  687.    */
  688.    function print()
  689.    {
  690.       //trace( "print()" )
  691.  
  692.       top.TopicFrame.print()
  693.    }
  694.  
  695. // End class definition: system.
  696.  
  697. /*
  698. DESCR:   Help topic class.
  699. PARAMS:  URL  The non-nethelp form of the URL.
  700. RETURNS: 
  701. NOTES:   
  702. */
  703. function helpTopic( URL )
  704. {
  705.    //trace( "helpTopic constructor" )
  706.  
  707.    assert( ( URL.toLowerCase().indexOf( ".htm" ) > -1 ),
  708.            TOPIC_URL_VALUE + URL )
  709.  
  710.    this.headerURL
  711.  
  712.    this.URL = URL
  713.  
  714.    this.fragmentSpec = URL.substring( URL.lastIndexOf( "#" ) + 1 )
  715.    assert( this.fragmentSpec != "", FRAG_SPEC )
  716.  
  717.    //this.aSecWnds = new Array()  // Secondary windows.
  718.  
  719.    this.destruct         = destruct
  720.    //this.addSecondary     = addSecondary
  721.    //this.closeSecondaries = closeSecondaries
  722.  
  723.    // Determine header URL by naming convention.
  724.    var extPos
  725.    extentionPos = this.URL.indexOf( ".htm" )
  726.    if ( extentionPos == -1 ) extentionPos = this.URL.indexOf( ".HTM" )
  727.    assert( ( extentionPos != -1 ), TOPIC_FILENAME )
  728. //   this.headerURL = this.URL.substring( 0, extentionPos ) + "Hdr.htm"
  729.  
  730.    // Load URL in the topic frame.
  731.    top.TopicFrame.location.replace( this.URL )
  732. }
  733.  
  734.    /*
  735.    DESCR:   Adds a secondary window.
  736.    PARAMS:  URL       The content URL.
  737.             name      The window name.
  738.             features  The feature string.
  739.    RETURNS: 
  740.    NOTES:   
  741.    */
  742.    /*
  743.    function addSecondary( URL, name, features )
  744.    {
  745.       //trace( "addSecondary()" )
  746.  
  747.       var newWnd = window.open( URL, name, features )
  748.       
  749.       // Add window to list only if it is a new window (user may
  750.       // create a secondary more than once).
  751.       for ( var i = 0; i < this.aSecWnds.length; i++ ) {
  752.          if ( this.aSecWnds[ i ] == newWnd ) return newWnd
  753.       }
  754.       this.aSecWnds[ this.aSecWnds.length ] = newWnd
  755.  
  756.       return newWnd
  757.    }
  758.    */
  759.  
  760.    /*
  761.    DESCR:   Closes all secondary windows.
  762.    PARAMS:  
  763.    RETURNS: 
  764.    NOTES:   
  765.    */
  766.    /*
  767.    function closeSecondaries()
  768.    {
  769.       //trace( "closeSecondaries()" )
  770.  
  771.       for ( var i = 0; i < this.aSecWnds.length; i++ ) {
  772.          if ( defined( this.aSecWnds[ i ] ) ) this.aSecWnds[ i ].close()
  773.       }
  774.    }
  775.    */
  776.    
  777.    /*
  778.    DESCR:   "Destructor."
  779.    PARAMS:  
  780.    RETURNS: 
  781.    NOTES:   
  782.    */
  783.    function destruct()
  784.    {
  785.       //trace( "helpTopic destruct()" )
  786.  
  787.       // Close any secondary windows owned by current topic.
  788.       //this.closeSecondaries()
  789.    }
  790.  
  791. // End class definition: helpTopic.
  792.  
  793. /*
  794. DESCR:   Popup class.
  795. PARAMS:  
  796. RETURNS: 
  797. NOTES:   
  798. */
  799.  
  800. // End class definition: popup.
  801.